﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Linq.Expressions;

using HST.Domain.Seedwork.Specifications;

namespace HST.Domain.Seedwork
{
    public interface IRepository<TAggregateRoot, TKey> : IDisposable
        where TAggregateRoot : AggregateRoot<TKey>
        where TKey : IEquatable<TKey>
    {
        /// <summary>
        /// Get the unit of work in this repository
        /// </summary>
        IUnitOfWork UnitOfWork { get; }

        /// <summary>
        /// Add item into repository
        /// </summary>
        /// <param name="item">Item to add to repository</param>
        void Add(TAggregateRoot aggregateRoot);

        /// <summary>
        /// Delete item 
        /// </summary>
        /// <param name="item">Item to delete</param>
        void Remove(TAggregateRoot aggregateRoot);

        /// <summary>
        /// Delete all elements of type TAggregateRoot in repository
        /// </summary>
        /// <param name="filter">Filter that each element do match</param>
        void Remove(Expression<Func<TAggregateRoot, bool>> filter);

        /// <summary>
        /// Delete all elements of type TAggregateRoot in repository
        /// </summary>
        /// <param name="specification">Specified that each element do match</param>
        void Remove(ISpecification<TAggregateRoot> specification);

        /// <summary>
        /// Set item as modified
        /// </summary>
        /// <param name="item">Item to modify</param>
        void Modify(TAggregateRoot aggregateRoot);

        /// <summary>
        /// Get one single element of type TAggregateRoot in repository
        /// </summary>
        /// <param name="filter">Filter that each element do match</param>
        /// <returns>One single of selected element</returns>
        TAggregateRoot GetSingle(Expression<Func<TAggregateRoot, bool>> filter);

        /// <summary>
        /// Get one single element of type TAggregateRoot in repository
        /// </summary>
        /// <param name="specification"></param>
        /// <param name="specification">Specified that each element do match</param>
        TAggregateRoot GetSingle(ISpecification<TAggregateRoot> specification);

        /// <summary>
        /// Get all elements of type TAggregateRoot in repository
        /// </summary>
        /// <returns>List of selected elements</returns>
        IEnumerable<TAggregateRoot> GetAll();

        /// <summary>
        /// Get all elements of type TAggregateRoot in repository
        /// </summary>
        /// <param name="pageIndex">Page index</param>
        /// <param name="pageSize">Number of elements in each page</param>
        /// <param name="orderByExpression">Order by expression for this query</param>
        /// <param name="order">Order by</param>
        /// <returns>List of selected elements</returns>
        IEnumerable<TAggregateRoot> GetAllPaged<KProperty>(Expression<Func<TAggregateRoot, KProperty>> orderByExpression, HST.Domain.Seedwork.Enumerators.Order order, int pageIndex, int pageSize, out int totalRecords);

        /// <summary>
        /// Get  elements of type TAggregateRoot in repository
        /// </summary>
        /// <param name="filter">Filter that each element do match</param>
        /// <returns>List of selected elements</returns>
        IEnumerable<TAggregateRoot> GetFiltered(Expression<Func<TAggregateRoot, bool>> filter);

        IEnumerable<TAggregateRoot> GetFiltered(ISpecification<TAggregateRoot> specification);

        IEnumerable<TAggregateRoot> GetFilterPaged<KProperty>(Expression<Func<TAggregateRoot, bool>> filter, Expression<Func<TAggregateRoot, KProperty>> orderByExpression, HST.Domain.Seedwork.Enumerators.Order order, int pageIndex, int pageSize, out int totalRecords);

        IEnumerable<TAggregateRoot> GetFilterPaged<KProperty>(ISpecification<TAggregateRoot> specification, Expression<Func<TAggregateRoot, KProperty>> orderByExpression, HST.Domain.Seedwork.Enumerators.Order order, int pageIndex, int pageSize, out int totalRecords);
    }
}
